# -*- coding: utf-8 -*-
from __future__ import print_function

import time
from decimal import Decimal

from dtrader.event import EventType

try:
    import Queue as queue
except ImportError:
    import queue


class Backtest(object):
    """
    事件驱动回测
    """
    def __init__(
        self,price_handler,
        strategy, portfolio_handler,
        broker, risk_manager,
        statistics,
        equity=Decimal("1000000.00"),
        heartbeat=0.0, max_iters=10000000000
    ):
        """
        初始化设置
        """

        self.price_handler = price_handler
        self.strategy = strategy
        self.portfolio_handler = portfolio_handler
        self.broker = broker
        self.risk_manager = risk_manager
        self.statistics = statistics
        self.equity = equity
        self.heartbeat = heartbeat
        self.max_iters = max_iters
        self.events_queue = price_handler.events_queue
        self.cur_time = None

    def _run_backtest(self):
        """
        创建事件循环，进行回测，循环会休息设定的"heartbeat"时间
        """
        print("Running Backtest...")
        iters = 0
        ticks = 0
        bars = 0
        while iters < self.max_iters and self.price_handler.continue_backtest:
            try:
                event = self.events_queue.get(False)
            except queue.Empty:
                self.price_handler.stream_next()
            else:
                if event is not None:
                    if event.type == EventType.TICK:
                        self.cur_time = event.time
                        self.strategy.calculate_signals(event)
                        self.portfolio_handler.update_portfolio_value()
                        self.statistics.update(event.time)
                        ticks += 1
                    elif event.type == EventType.BAR:
                        self.cur_time = event.time
                        self.strategy.calculate_signals(event)
                        self.portfolio_handler.update_portfolio_value()
                        self.statistics.update(event.time)
                        bars += 1
                    elif event.type == EventType.SIGNAL:
                        self.portfolio_handler.on_signal(event)
                    elif event.type == EventType.ORDER:
                        self.broker.execute_order(event)
                    elif event.type == EventType.FILL:
                        self.portfolio_handler.on_fill(event)
                    else:
                        raise NotImplemented("Unsupported event.type '%s'" % event.type)
            time.sleep(self.heartbeat)
            iters += 1

    def simulate_trading(self, testing=False):
        """
        运行策略完了用统计模块来评估策略
        """
        self._run_backtest()
        results = self.statistics.get_results()
        print("Backtest complete.")
        print("Sharpe Ratio: %s" % results["sharpe"])
        print("Max Drawdown: %s" % results["max_drawdown"])
        print("Max Drawdown Pct: %s" % results["max_drawdown_pct"])
        if not testing:
            self.statistics.plot_results()
        return results
